﻿using System;
using System.Runtime.InteropServices;

namespace Mrkz.ImageManipulation
{
    public class Pixel : IEquatable<Pixel>, IArithmeticOperation<Pixel>, IEquatableWithTolerance<Pixel>,IPixel
    {        
        double b;
        double g;
        double r;
        double a;

        public Pixel()
        {
            b = 0;
            g = 0;
            r = 0;
            a = 255;
        }   

        public Pixel(double R, double G, double B)
        {               
            this.r = (byte) R;
            this.g =(byte) G;
            this.b =(byte) B;
            this.a = 255;
        }

        public static Pixel operator +(Pixel A, Pixel B)
        {
            Pixel r = new Pixel();

            r.a = (byte) (A.a + B.a);
            r.r = (byte)(A.r + B.r);
            r.g = (byte)(A.g + B.g);
            r.b= (byte)(A.b + B.b);

            return r;
        }

        public bool Equals(Pixel other, int tolerance)
        {
            if (Math.Abs(other.a - a) <= tolerance
                && Math.Abs(other.r - r) <= tolerance
                && Math.Abs(other.b - b) <= tolerance
                && Math.Abs(other.g - g) <= tolerance )
                return true;

            return false;
        }

        public bool Equals(Pixel other)
        {
            return Equals(other, 0);            
        }

        public Pixel Add(Pixel B)
        {
            Pixel p = new Pixel();
            p.a = (byte)Saturate0255(a + B.a);
            p.r = (byte)Saturate0255(r + B.r);
            p.g = (byte)Saturate0255(g + B.g);
            p.b = (byte)Saturate0255(b + B.b);
            return p;
        }

        public Pixel Subtract(Pixel B)
        {
            Pixel p = new Pixel();
            p.a = (byte)Saturate0255(a - B.a);
            p.r   = (byte)Saturate0255(r - B.r);
            p.g = (byte)Saturate0255(g- B.g);
            p.b  = (byte)Saturate0255(b - B.b);
            return p;
        }       

        public double Red
        {
            get
            {
                return r;
            }
            set
            {
                r = (byte)value;
            }
        }

        public double Green
        {
            get
            {
                return g;
            }
            set
            {
                g = (byte)value;
            }
        }

        public double Blue
        {
            get
            {
                return b;
            }
            set
            {
                b = (byte)value;
            }
        }

        public double Alpha
        {
            get
            {
                return a;
            }
            set
            {
                a = (byte)value;
            }
        }

        Pixel IArithmeticOperation<Pixel>.Multiply(double d)
        {
            throw new NotImplementedException();
        }

        public Pixel Multiply(double d)
        {
            return new Pixel(Saturate0255(Red * d), Saturate0255(Green * d), Saturate0255(Blue * d));
        }

        public Pixel Multiply(double mR, double mG, double mB)
        {
            return new Pixel(Saturate0255(Red * mR),Saturate0255(Green * mG), Saturate0255(Blue * mB));
        }

        static double Saturate0255(double v)
        {
            if (v >= 255)
                return 255;
            if (v <= 0)
                return 0;

            return v;
        }
    }

    public class PixelColors
    {
        public static Pixel Black = new Pixel(); 
    }
}
